package com.ydlclass.handler;

import com.ydlclass.bootstrap.ServiceBootstrap;
import com.ydlclass.message.MessageType;
import com.ydlclass.message.MetaData;
import com.ydlclass.message.MethodKey;
import com.ydlclass.message.YrpcMessage;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;

/**
 * @author it楠老师
 * @createTime 2023-03-16
 */
@Slf4j
public class YrpcRequestMessageHandler extends SimpleChannelInboundHandler<YrpcMessage> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, YrpcMessage yrpcRequestMessage) throws Exception {

        if (yrpcRequestMessage.getMessageType() != MessageType.REQUEST.getValue()){
            return;
        }

        // 服务端接受到消息，解析处理
        MetaData metaData = (MetaData)yrpcRequestMessage.getPayload();
        Object returnValue = callTargetMethod(metaData);
        InetSocketAddress socketAddress = (InetSocketAddress)channelHandlerContext.channel().remoteAddress();
        if(log.isDebugEnabled()){
            String methodKey = metaData.getInterfaceName() + metaData.getMethodName();
            log.debug("----> The remote client[{}] requests to invoke the method[{}]--requestId[{}]!",
                    socketAddress,methodKey,yrpcRequestMessage.getRequestId());
        }

        // todo 包装成YrpcMessage，需要设置序列化方式，和压缩方式
        YrpcMessage yrpcResponseMessage = new YrpcMessage();
        // todo client --> RequestId :  server --> new ? clientRequestId  : client --> suspend
        yrpcResponseMessage.setRequestId(yrpcRequestMessage.getRequestId());
        yrpcResponseMessage.setPayload(returnValue);
        yrpcResponseMessage.setCompressTye(yrpcRequestMessage.getCompressTye());
        yrpcResponseMessage.setMessageType(MessageType.RESPONSE.getValue());
        yrpcResponseMessage.setSerializeType(yrpcRequestMessage.getSerializeType());

        if(log.isDebugEnabled()){
            String methodKey = metaData.getInterfaceName() + metaData.getMethodName();
            log.debug("----> Method[{}] -- requestId[{}] call was successful and an attempt was made to send to the client[{}]!",
                    methodKey,yrpcRequestMessage.getRequestId(),socketAddress);
        }
        // 返还给客户端
        channelHandlerContext.writeAndFlush(yrpcResponseMessage);
    }

    private Object callTargetMethod(MetaData metaData){
        // 获得方法的key
        MethodKey methodKey = new MethodKey(
                metaData.getInterfaceName(),
                metaData.getMethodName(),
                metaData.getParameterTypes()
        );
        // 获取暴露的对象实例
        Object instance = ServiceBootstrap.getInstance()
                .getExposeInstance(methodKey);
        try {
            // 获得方法，并执行调用过程
            Method method = instance.getClass().getMethod(
                    methodKey.getMethodName(),
                    methodKey.getParameterTypes()
            );
            return method.invoke(instance, metaData.getParameterValue());
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

}
